package com.example.shop.es.service;

import com.example.shop.es.dto.ElasticSearchQueryParam;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Query;

import java.util.List;
import java.util.Map;

public interface ElasticSearchClient {

//===================================  索引(相当于表)  ===================================//
    /**
     * 根据class上的Document的indexName创建class对应的索引
     * @param tClass @Document注解标记的类
     * @return 返回创建状态，如果创建成功，则返回true。如果索引已经存在，则返回true
     */
    boolean createIndex(Class<?> tClass);

    /**
     * 根据class上的Document的indexName删除对应的索引
     * @param tClass @Document注解标记的类
     * @return
     */
    boolean deleteIndex(Class<?> tClass);

    /**
     * 为指定class上Document对应的索引创建别名
     * 如果别名存在，则会删除存在的别名后，在添加该别名
     * @param tClass @Document注解标记的类
     * @param aliasName 别名
     * @return 返回创建别名状态，起成功，则返回true
     */
    boolean addIndexAlias(Class<?> tClass,String aliasName);

    /**
     * 判断指定索引是否存在
     * @param tClass @Document注解标记的类
     * @return 返回存在性，如果存在，则返回true
     */
    boolean existIndex(Class<?> tClass);

//===================================  文档(相当于记录)  ===================================//

    /**
     * 插入一条记录，到data对应类的索引中。
     * 如果记录存在，则直接替换掉，即会覆盖
     * @param data 插入的记录
     * @return 返回插入状态，如果插入成功，则返回true
     */
    boolean saveDocument(Object data);

    /**
     * 插入一条记录，到data对应类的索引中。
     * 如果记录存在，则直接替换掉，即会覆盖
     * @param data 插入的记录
     * @param refreshPolicy es数据更新策略。
     * @return 返回插入状态，如果插入成功，则返回true
     */
    boolean saveDocument(Object data,WriteRequest.RefreshPolicy refreshPolicy);

    /**
     * 更新data对应的文档数据。即data必须要指定id。因为是根据id进行的
     * 当data中的字段值为null时，则是不会更新文档中的数据为null的
     * @param data 要更新的文档数据
     * @return 返回更新状态，更新成功返回true
     */
    boolean updateDocument(Object data);

    /**
     * 更新data对应的文档数据。即data必须要指定id。因为是根据id进行的。
     * 更新时，会进行条件判断，如果符合script，则进行更新，否则不更新
     * 如果要进行脚本更新，则data只要传入只具有id的该对象即可，根据脚本更新
     * @param data 要更新的文档数据,必须指定文档id，即id
     * @param script 脚本条件
     * @param params 脚本参数
     * @return 返回更新状态，更新成功返回true
     */
    boolean updateDocument(Object data, String script, Map<String, Object> params);
    /**
     * 根据文档id，删除tClass对应的索引里的记录
     * @param deleteDocument 传入一个只带id的@Document注解标记的类的对象
     */
    void deleteDocument(Object deleteDocument);

    /**
     * 根据条件，删除所有符合条件的文档
     * @param tClass @Document注解标记的类。如果要删除不同的索引里文档，则tClass要求为Object
     * @param queryBuilder 条件
     * @param indexNames 要删除的索引
     */
    void deleteDocument(QueryBuilder queryBuilder,Class<?> tClass,String...indexNames);

    /**
     * 获取tClass索引里指定的文档id的文档
     * @param <T> 返回的记录类型
     * @param tClass @Document注解标记的类。也是返回的T类型的class
     * @param id 文档id
     * @return 返回文档id对应的记录
     */
    <T> T getDocument(long id,Class<T> tClass);

    /**
     * 获取指定id且类型为tClass的es数据
     * @param id 指定id
     * @param tClass 指定类型
     * @param <T> 返回类型
     * @return 返回数据，如果获取不到则返回null
     */
    <T> T getDocumentMustClass(long id,Class<T> tClass);

    /**
     * 根据tClass对应的索引，来判断该索引上的指定id是否存在
     * @param id 文档id
     * @param tClass @Document注解标记的类。
     * @return 返回存在性，如果存在，则返回true
     */
    boolean existDocument(long id, Class<?> tClass);


//===================================  批处理  ===================================//

    /**
     * 批量插入数据。
     * 如果记录存在，则会替换掉，否则插入
     * @param dataList 插入的数据
     * @param refreshPolicy 插入后，es服务器更新数据的刷新策略 {@link WriteRequest.RefreshPolicy}
     *      NONE：请求向ElasticSearch提交了数据，不管数据是否已经完成刷新，直接结束请求。
     *                      优点：操作延时短、资源消耗低。缺点：实时性低。
     *      IMMEDIATE：请求向ElasticSearch提交了数据，立即进行数据刷新，然后再结束请求。
     *                      优点：实时性高、操作延时短。缺点：资源消耗高。
     *      WAIT_UNTIL：请求向ElasticSearch提交了数据，等待数据完成刷新，然后再结束请求。
     *                      优点：实时性高、操作延时长。缺点：资源消耗低。
     * @param <T> 保证list里存放的数据都是同一种
     * @return 返回批处理状态，如果全部成功，则返回true，否则返回false
     */
    <T> boolean bulkSave(List<T> dataList, WriteRequest.RefreshPolicy refreshPolicy);

    /**
     * 批量更新数据。
     * 如果dataList中存放元素的字段值有为null的，则会不对其进行更新为null
     * @param dataList 更新的数据
     * @param refreshPolicy es服务器更新数据的刷新策略
     * @param <T> 元素类型。@Document注解标记的类型。
     */
    <T> void bulkUpdate(List<T> dataList, WriteRequest.RefreshPolicy refreshPolicy);

//===================================  搜索  ===================================//

    /**
     * 根据ElasticSearchQueryParam查询参数进行条件查询
     * @param tClass 查询返回的类型的class
     * @param queryParam 查询条件
     * @param <T> 返回的类型
     * @return 返回查询结果
     */
    <T> List<T> search( ElasticSearchQueryParam queryParam,Class<T> tClass);

    /**
     *
     * @param queryParamList
     * @param clazz
     * @param <T>
     * @return
     */
    <T> List<T> multiSearch(List<ElasticSearchQueryParam> queryParamList, Class<T> clazz);
    /**
     * 根据条件查询，并统计符合条件的数据行数
     * @param tClass @Document注解标记的类型。
     * @param queryParam 查询条件
     * @return 返回符合条件的数据行数
     */
    Long count(Class<?> tClass, ElasticSearchQueryParam queryParam);

//===================================  地理位置查询  ===================================//

}
